CREATE schema auditoria;
REVOKE CREATE ON schema auditoria FROM public;
 
CREATE TABLE auditoria.acciones_alfinte (
    nombre_esquema text NOT NULL,
    nombre_tabla text NOT NULL,
    nombre_usuario text,
    fecha_hora timestamp WITH time zone NOT NULL DEFAULT current_timestamp,
    accion_realizada TEXT NOT NULL CHECK (accion_realizada IN ('INSERTAR','ELIMINAR','ACTUALIZAR')),
    dato_antiguo text,
    nuevo_dato text,
    query text
) WITH (fillfactor=100);
 
REVOKE ALL ON auditoria.acciones_alfinte FROM public;
 
GRANT SELECT ON auditoria.acciones_alfinte TO public;
 
CREATE INDEX acciones_alfinte_schema_table_idx 
ON auditoria.acciones_alfinte(((nombre_esquema||'.'||nombre_tabla)::TEXT));
 
CREATE INDEX acciones_alfinte_fecha_hora_idx 
ON auditoria.acciones_alfinte(fecha_hora);
 
CREATE INDEX acciones_alfinte_accion_realizada_idx 
ON auditoria.acciones_alfinte(accion_realizada);

CREATE OR REPLACE FUNCTION auditoria.datos_modificados() RETURNS TRIGGER AS $body$
DECLARE
    v_old_data TEXT;
    v_nuevo_dato TEXT;
	
BEGIN
 
    IF (TG_OP = 'UPDATE') THEN
        v_old_data := ROW(OLD.*);
        v_nuevo_dato := ROW(NEW.*);
        INSERT INTO auditoria.acciones_alfinte (nombre_esquema,nombre_tabla,nombre_usuario,accion_realizada,dato_antiguo,nuevo_dato,query) 
        VALUES (TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT,session_user::TEXT,substring(TG_OP,1,1),v_old_data,v_nuevo_dato, current_query());
        RETURN NEW;
    ELSIF (TG_OP = 'DELETE') THEN
        v_old_data := ROW(OLD.*);
        INSERT INTO auditoria.acciones_alfinte (nombre_esquema,nombre_tabla,nombre_usuario,accion_realizada,dato_antiguo,query)
        VALUES (TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT,session_user::TEXT,substring(TG_OP,1,1),v_old_data, current_query());
        RETURN OLD;
    ELSIF (TG_OP = 'INSERT') THEN
        v_nuevo_dato := ROW(NEW.*);
        INSERT INTO auditoria.acciones_alfinte (nombre_esquema,nombre_tabla,nombre_usuario,accion_realizada,nuevo_dato,query)
        VALUES (TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT,session_user::TEXT,substring(TG_OP,1,1),v_nuevo_dato, current_query());
        RETURN NEW;
    ELSE
        RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - Other accion_realizada occurred: %, at %',TG_OP,now();
        RETURN NULL;
    END IF;
 
EXCEPTION
    WHEN data_exception THEN
        RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - UDF ERROR [DATA EXCEPTION] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
    WHEN unique_violation THEN
        RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - UDF ERROR [UNIQUE] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
    WHEN OTHERS THEN
        RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - UDF ERROR [OTHER] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
END;
$body$
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = pg_catalog, auditoria;


CREATE TRIGGER t_if_modified_trg 
 AFTER INSERT OR UPDATE OR DELETE ON t
 FOR EACH ROW EXECUTE PROCEDURE auditoria.datos_modificados();